package com.flyox.game.militarychess.util.ssl;

import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.Security;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;

public class SslContextFactory {

	/**
	 * Protocol to use.
	 */
	private static final String PROTOCOL = "TLS";

	private static final String KEY_MANAGER_FACTORY_ALGORITHM;

	static {
		String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm");
		if (algorithm == null) {
			algorithm = "SunX509";
		}

		KEY_MANAGER_FACTORY_ALGORITHM = algorithm;
	}

	/**
	 * Server certificate keystore file name.
	 */
	private static final String FLYOX_KEYSTORE = "flyox.cert";

	// NOTE: The keystore was generated using keytool:
	// keytool -genkey -alias flyox -keysize 512 -validity 3650 -keyalg RSA -dname "CN=www.flyox.com, OU=XXX CA, O=flyox Inc, L=Stockholm, S=Stockholm, C=SE" -keypass flyoxpw -storepass flyoxpw -keystore flyox.cert
	/**
	 * keystore password.
	 */
	private static final char[] FLYOX_PW = { 'f', 'l', 'y', 'o', 'x', 'p', 'w' };

	private static SSLContext serverInstance = null;

	private static SSLContext clientInstance = null;

	/**
	 * Get SSLContext singleton.
	 * 
	 * @return SSLContext
	 * @throws java.security.GeneralSecurityException
	 * 
	 */
	public static SSLContext getInstance(boolean server) throws GeneralSecurityException {
		SSLContext retInstance = null;
		if (server) {
			if (serverInstance == null) {
				synchronized (SslContextFactory.class) {
					if (serverInstance == null) {
						try {
							serverInstance = createServerSslContext();
						} catch (Exception ioe) {
							throw new GeneralSecurityException("Can't create Server SSLContext:" + ioe);
						}
					}
				}
			}
			retInstance = serverInstance;
		} else {
			if (clientInstance == null) {
				synchronized (SslContextFactory.class) {
					if (clientInstance == null) {
						clientInstance = createClientSslContext();
					}
				}
			}
			retInstance = clientInstance;
		}
		return retInstance;
	}

	private static SSLContext createServerSslContext() throws GeneralSecurityException, IOException {
		// Create keystore
		KeyStore ks = KeyStore.getInstance("JKS");
		InputStream in = null;
		try {
			in = SslContextFactory.class.getResourceAsStream(FLYOX_KEYSTORE);
			ks.load(in, FLYOX_PW);
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException ignored) {
				}
			}
		}

		// Set up key manager factory to use our key store
		KeyManagerFactory kmf = KeyManagerFactory.getInstance(KEY_MANAGER_FACTORY_ALGORITHM);
		kmf.init(ks, FLYOX_PW);

		// Initialize the SSLContext to work with our key managers.
		SSLContext sslContext = SSLContext.getInstance(PROTOCOL);
		sslContext.init(kmf.getKeyManagers(), TrustManagerFactory.X509_MANAGERS, null);

		return sslContext;
	}

	private static SSLContext createClientSslContext() throws GeneralSecurityException {
		SSLContext context = SSLContext.getInstance(PROTOCOL);
		context.init(null, TrustManagerFactory.X509_MANAGERS, null);
		return context;
	}

}
